package cn.chenfei.sshd.client.common;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.util.StrUtil;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClientFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class SimpleSshClient {

    private SshClient client;
    private ClientSession clientSession;
    private SftpClient sftp;
    //

    public SimpleSshClient() {
    }

    public boolean connect(SshConnect sshConnect) {
        try {
            // 如果会话已成功完成身份验证阶段，则为True
            if (clientSession != null && clientSession.isAuthenticated()) {
                return true;
            }
            client = SshClient.setUpDefaultClient();
            client.start();
            clientSession = client.connect(sshConnect.getName(), sshConnect.getHost(), sshConnect.getPort()).verify().getSession();
            clientSession.addPasswordIdentity(sshConnect.getPassword());
            boolean isSuccess = clientSession.auth().verify().isSuccess();
            if (isSuccess) {
                // 创建sftp客户端
                sftp = SftpClientFactory.instance().createSftpClient(clientSession);
            }
            return isSuccess;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 执行命令
     *
     * @param command
     * @return
     */
    public CommandResult command(String command) {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
             ByteArrayOutputStream err = new ByteArrayOutputStream()) {
            clientSession.executeRemoteCommand(command, out, err, StandardCharsets.UTF_8);
            String outString = out.toString();
            String errString = err.toString();
            return new CommandResult(outString,errString);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 删除文件
     *
     * @param path
     * @throws IOException
     */
    public void remove(String path) throws IOException {
        sftp.remove(path);
    }

    /**
     * 删除文件夹
     *
     * @param path
     */
    public void rmdir(String path) throws IOException {
        sftp.rmdir(path);
    }

    /**
     * 创建文件夹
     *
     * @param path
     * @throws IOException
     */
    public void mkdir(String path) throws IOException {
        sftp.mkdir(path);
    }

    /**
     * 更新远程节点元数据
     *
     * @param path
     * @param attributes
     * @throws IOException
     */
    public void setAttributes(String path, SftpClient.Attributes attributes) throws IOException {
        sftp.setStat(path, attributes);
    }

    /**
     * 获取path下的条目
     *
     * @param path
     * @return
     * @throws IOException
     */
    public List<DirInfo> readEntries(String path, String... filter) throws IOException {
        return sftp.readEntries(path).stream().filter(v -> !StrUtil.equalsAny(v.getFilename(), filter)).map(dirEntry -> new DirInfo(dirEntry.getFilename(), dirEntry.getAttributes())).collect(Collectors.toList());
    }

    /**
     * 重命名文件夹名称或文件名称
     *
     * @param oldPath
     * @param newPath
     * @throws IOException
     */
    public void rename(String oldPath, String newPath) throws IOException {
        sftp.rename(oldPath, newPath);
    }

    /**
     * 上传文件
     *
     * @param input
     * @param output
     * @param progress
     */
    public void upload(String input, String output, Consumer<Long> progress) {
        try (OutputStream outputStream = sftp.write(output);
             FileInputStream inputStream = new FileInputStream(input)) {
            copy(inputStream, outputStream, progress);
        } catch (IOException | IORuntimeException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 下载文件
     *
     * @param input
     * @param output
     * @param progress
     */
    public void download(String input, String output, Consumer<Long> progress) {
        try (InputStream inputStream = sftp.read(input);
             FileOutputStream outputStream = new FileOutputStream(output)) {
            copy(inputStream, outputStream, progress);
        } catch (IOException | IORuntimeException e) {
            throw new RuntimeException(e);
        }
    }

    private void copy(InputStream in, OutputStream out, Consumer<Long> progress) {
        IoUtil.copy(in, out, 1024, new StreamProgress() {
            @Override
            public void start() {
                System.out.println("start ... ");
            }

            @Override
            public void progress(long total, long progressSize) {
                progress.accept(progressSize);
            }

            @Override
            public void finish() {
                System.out.println("finish ... ");
            }
        });
    }


    public void close() throws IOException {
        clientSession.close();
        client.close();
    }

}
